/*
 * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package java.io;

import java.util.Arrays;

/**
 * 这个类实现了一个输出流，其中数据被写入字节数组中。
 * 当数据写入缓冲区时，缓冲区会自动增长。
 * 可以使用toByteArray()和toString()获得数据。
 * <p>
 * 关闭ByteArrayOutputStream没有任何效果。
 * 该类中的方法可以在流被关闭后调用，而无需生成IOException。
 *
 * @author  Arthur van Hoff
 * @since   JDK1.0
 */

public class ByteArrayOutputStream extends OutputStream {

    /**
     * 存储数据的缓存
     */
    protected byte buf[];

    /**
     * 缓冲区中的有效字节数。
     */
    protected int count;

    /**
     * 创建一个新的ByteArrayOutputStream。
     * 缓冲区容量最初是32字节，但如果需要，它的大小会增加。
     */
    public ByteArrayOutputStream() {
        this(32);
    }

    /**
     * 创建新的ByteArrayOutputStream，具有指定大小的缓冲区容量(以字节为单位)。
     *
     * @param   size   the initial size.
     * @exception  IllegalArgumentException if size is negative.
     */
    public ByteArrayOutputStream(int size) {
        if (size < 0) {
            throw new IllegalArgumentException("Negative initial size: "
                                               + size);
        }
        // buf初始为size个字节
        buf = new byte[size];
    }

    /**
     * 如果需要，增加容量，以确保它至少可以保留minCapacity参数指定的元素数量。
     *
     * @param minCapacity the desired minimum capacity
     * @throws OutOfMemoryError if {@code minCapacity < 0}.  This is
     * interpreted as a request for the unsatisfiably large capacity
     * {@code (long) Integer.MAX_VALUE + (minCapacity - Integer.MAX_VALUE)}.
     */
    private void ensureCapacity(int minCapacity) {
        // overflow-conscious code
        if (minCapacity - buf.length > 0)
            grow(minCapacity);
    }

    /**
     * 要分配的数组的最大大小。一些虚拟机在数组中保留一些头部。
     * 尝试分配更大的数组可能会导致OutOfMemoryError:请求的数组大小超过VM限制。
     * Integer.MAX_VALUE - 8
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    /**
     * 增加容量，以确保它至少可以容纳minCapacity个元素。
     *
     * @param minCapacity the desired minimum capacity
     */
    private void grow(int minCapacity) {
        // overflow-conscious code
    	// 新的大小为min(2*oldCapacity,minCapacity,MAX_ARRAY_SIZE)
        int oldCapacity = buf.length;
        int newCapacity = oldCapacity << 1;
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // 复制buf到长度为newCapacity的新数组，然后赋值给buf
        buf = Arrays.copyOf(buf, newCapacity);
    }

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

    /**
     * 将指定的字节写入此字节数组输出流。
     *
     * @param   b   the byte to be written.
     */
    public synchronized void write(int b) {
    	// 先保证大小，然后count处设置b，然后count++
        ensureCapacity(count + 1);
        buf[count] = (byte) b;
        count += 1;
    }

    /**
     * 将从指定的字节数组off开始的len字节写入到这个字节数组输出流。
     *
     * @param   b     the data.
     * @param   off   the start offset in the data.
     * @param   len   the number of bytes to write.
     */
    public synchronized void write(byte b[], int off, int len) {
        if ((off < 0) || (off > b.length) || (len < 0) ||
            ((off + len) - b.length > 0)) {
            throw new IndexOutOfBoundsException();
        }
        // 从b的off开始，复制到buf的count处，总共len个字节
        ensureCapacity(count + len);
        System.arraycopy(b, off, buf, count, len);
        count += len;
    }

    /**
     * 将这个字节数组输出流的完整内容写入指定的输出流参数，
     * 就像使用out.write(buf, 0, count)方法一样。
     *
     * @param      out   the output stream to which to write the data.
     * @exception  IOException  if an I/O error occurs.
     */
    public synchronized void writeTo(OutputStream out) throws IOException {
        out.write(buf, 0, count);
    }

    /**
     * 将这个ByteArrayInputStream的count字段重置为零，
     * 这样输出流中当前累积的所有输出都将被丢弃。
     * 可以再次使用输出流，重用已经分配的缓冲区空间。
     *
     * @see     java.io.ByteArrayInputStream#count
     */
    public synchronized void reset() {
        count = 0;
    }

    /**
     * 创建一个新分配的字节数组。
     * 它的大小是这个输出流的size，缓存的有效内容已经复制到其中。
     *
     * @return  the current contents of this output stream, as a byte array.
     * @see     java.io.ByteArrayOutputStream#size()
     */
    public synchronized byte toByteArray()[] {
        return Arrays.copyOf(buf, count);
    }

    /**
     * 返回buffer的目前大小
     *
     * @return  the value of the <code>count</code> field, which is the number
     *          of valid bytes in this output stream.
     * @see     java.io.ByteArrayOutputStream#count
     */
    public synchronized int size() {
        return count;
    }

    /**
     * 使用平台的默认字符集将缓冲区的内容转换为字符串。
     * 新字符串的长度是character set的函数，因此可能不等于缓冲区的大小。
     *
     * <p> 这个方法总是用平台默认字符集的默认替换字符串替换malformed-input和unmappable- character序列。
     * 当需要对译码过程进行更多控制时，应该使用CharsetDecoderclass。
     *
     * @return String decoded from the buffer's contents.
     * @since  JDK1.1
     */
    public synchronized String toString() {
    	// buf的0-count变成string
        return new String(buf, 0, count);
    }

    /**
     * 通过使用指定charsetName解码字节，将缓冲区的内容转换为字符串。
     * 新字符串的长度是charset的函数，因此可能不等于字节数组的长度。
     *
     * <p> 此方法总是将malformed-input和unmappable-character序列替换为该字符集的默认替换字符串。
     * java.nio.charset类当需要更多的控制解码过程时，应该使用CharsetDecoder类。
     *
     * @param      charsetName  the name of a supported
     *             {@link java.nio.charset.Charset charset}
     * @return     String decoded from the buffer's contents.
     * @exception  UnsupportedEncodingException
     *             If the named charset is not supported
     * @since      JDK1.1
     */
    public synchronized String toString(String charsetName)
        throws UnsupportedEncodingException
    {
        return new String(buf, 0, count, charsetName);
    }

    /**
     * 创建一个新分配的字符串。
     * 它的大小是输出流的当前大小，缓冲区的有效内容已经被嵌入其中。
     * 结果字符串中的每个字符c都是由字节数组中对应的元素b构造的，这样:
     * <blockquote><pre>
     *     c == (char)(((hibyte &amp; 0xff) &lt;&lt; 8) | (b &amp; 0xff))
     * </pre></blockquote>
     *
     * 弃用。此方法不能正确地将字节转换为字符。
     * 在JDK 1.1中，这样做的首选方法是通过toString(String enc)方法，
     * 它接受一个encoding-name参数，或者toString()方法，它使用平台的默认字符编码。
     *
     * @param      hibyte    the high byte of each resulting Unicode character.
     * @return     the current contents of the output stream, as a string.
     * @see        java.io.ByteArrayOutputStream#size()
     * @see        java.io.ByteArrayOutputStream#toString(String)
     * @see        java.io.ByteArrayOutputStream#toString()
     */
    @Deprecated
    public synchronized String toString(int hibyte) {
        return new String(buf, hibyte, 0, count);
    }

    /**
     * 关闭ByteArrayOutputStream没有任何效果。
     * 该类中的方法可以在流被关闭后调用，而无需生成IOException。
     */
    public void close() throws IOException {
    }

}
